home *** CD-ROM | disk | FTP | other *** search
/ C/C++ Users Group Library 1996 July / C-C++ Users Group Library July 1996.iso / listings / v_09_09 / 9n09060a < prev    next >
Text File  |  1991-07-22  |  10KB  |  381 lines

  1. /*
  2.  * asn1.c -- functions for decoding encoded ASN.1
  3.  */
  4.  
  5. #include <stdlib.h>
  6. #include <stdio.h>
  7. #ifdef __STDC__
  8. #include <limits.h>
  9. #endif                          /* __STDC__ */
  10. #include <ctype.h>
  11. #include <string.h>
  12. #include "asn1.h"
  13.  
  14. #ifndef USHRT_MAX
  15. #define USHRT_MAX 65535
  16. #endif
  17.  
  18. #ifndef UINT_MAX
  19. #define UINT_MAX USHRT_MAX
  20. #endif
  21.  
  22. #ifndef SIZE_T_MAX
  23. #define SIZE_T_MAX UINT_MAX
  24. #endif
  25.  
  26. #define BOOLEAN_TYPE    1
  27. #define INTEGER_TYPE    2
  28. #define BITSTRING_TYPE  3
  29. #define NULL_TYPE       5
  30.  
  31. #ifndef TRUE
  32. #define FALSE 0
  33. #define TRUE 1
  34. #endif
  35.  
  36. #define BIT_8        128
  37. #define BIT_1          1
  38. #define BITS_54321    31
  39. #define BITS_7654321 127
  40.  
  41. #define punt(x) { printf(" -- %s\n", x); exit(1); }
  42.  
  43. #define the_class(x) (*x >> 6 & 3)
  44. #define the_complexity(x) ((*x >> 5) & BIT_1)
  45.  
  46. static unsigned int
  47. the_tag_number(encoding)
  48.     char          **encoding;
  49. /*
  50.  * This function returns the tag number of an ASN.1
  51.  * encoding. The argument must point to a pointer to
  52.  * the first octet of the encoding. The pointer is
  53.  * advanced to the first octet of the length of the
  54.  * encoding.
  55.  * 
  56.  * BUG: Tag numbers greater than UINT_MAX have their
  57.  * high order bits stripped.
  58.  */
  59. {
  60.     unsigned int    t;
  61.  
  62.     t = ((unsigned char) **encoding) & BITS_54321;
  63.     (*encoding)++;
  64.     if (BITS_54321 == t) {      /* high tag number? */
  65.         t = 0;
  66.         while (**encoding & BIT_8) {
  67.             t << = 7;
  68.             t |= **encoding & BITS_7654321;
  69.             (*encoding)++;
  70.         }
  71.         t << = 7;
  72.         t |= **encoding;
  73.         (*encoding)++;
  74.     }
  75.     return t;
  76. }
  77.  
  78. static          size_t
  79. the_length(encoding)
  80.     char          **encoding;
  81. /*
  82.  * This function returns the length of an ASN.1
  83.  * encoding. The pointer passed in must be pointing
  84.  * to the first length octet of the encoding. It has
  85.  * the side effect of advancing the pointer past the
  86.  * length octets of the encoding.
  87.  * 
  88.  * BUGS:
  89.  * 
  90.  * This routine does not handle indefinite encodings.
  91.  * i.e. A length octet of 0x80 causes SIZE_T_MAX to
  92.  * be returned. This is the same value that is
  93.  * returned when the length octets encode a length
  94.  * equal to the highest value for a size_t.
  95.  * 
  96.  * This function does not handle the definite form for
  97.  * values greater than SIZE_T_MAX. In this case it
  98.  * returns SIZE_T_MAX-1. The same value is returned
  99.  * when valid. This bug is unimportant with integers
  100.  * of 16 or more bits and data that is not expected
  101.  * to get longer than a couple kilobytes.
  102.  * 
  103.  */
  104. {
  105.     size_t          length;
  106.     short           n;
  107.  
  108.     length = 0;
  109.     if (BIT_8 == (**encoding))  /* indefinite form? */
  110.         length = SIZE_T_MAX;
  111.     else if (**encoding & BIT_8) {    /* long form? */
  112.         n = (short) (**encoding & BITS_7654321);
  113.         if (sizeof length < n)
  114.             length = SIZE_T_MAX - 1;  /* We can only
  115.                                        * take so
  116.                                        * much. */
  117.         else {
  118.             (*encoding)++;
  119.             for (; n; n--) {
  120.                 length << = 8;
  121.                 length |= (unsigned char) **encoding;
  122.                 (*encoding)++;
  123.             }
  124.         }
  125.     } else {                    /* short form */
  126.         length = (unsigned char) **encoding;
  127.         (*encoding)++;
  128.     }
  129.     return length;
  130. }
  131.  
  132. static int
  133. isprintable(c)
  134.     int             c;
  135. /*
  136.  * This is different from the standard C function
  137.  * isprint.  This only allows characters that can be
  138.  * in an ASN.1 PrintableString (universal type 19.)
  139.  */
  140. {
  141.     if (isalpha(c))
  142.         return TRUE;
  143.     if (isdigit(c))
  144.         return TRUE;
  145.     if (NULL != strrchr(" '()+,-./:=?", c))
  146.         return TRUE;
  147.     return FALSE;
  148. }
  149.  
  150. static void
  151. show_string(string, length)
  152.     char           *string;
  153.     size_t          length;
  154. {
  155.     size_t          i;
  156.     unsigned char   c;
  157.  
  158.     putchar('\"');
  159.     for (i = 0; i < length; i++) {
  160.         c = string[i];
  161.         if (isprint(c) && (127 > c)) {
  162.             switch (c) {
  163.             case '\\':
  164.             case '\"':
  165.                 putchar('\\');
  166.             default:
  167.                 putchar(c);
  168.             }
  169.         } else if (iscntrl(c)) {
  170.             putchar('\\');
  171.             switch (c) {
  172.             case '\a':
  173.                 putchar('a');
  174.                 break;
  175.             case '\b':
  176.                 putchar('b');
  177.                 break;
  178.             case '\f':
  179.                 putchar('f');
  180.                 break;
  181.             case '\n':
  182.                 putchar('n');
  183.                 break;
  184.             case '\r':
  185.                 putchar('r');
  186.                 break;
  187.             case '\t':
  188.                 putchar('t');
  189.                 break;
  190.             case '\v':
  191.                 putchar('v');
  192.                 break;
  193.             default:
  194.                 printf("x%02hX", c);
  195.             }
  196.         } else
  197.             printf("\\x%02hX", c);
  198.     }
  199.     putchar('\"');
  200. }
  201.  
  202. static void
  203. show_hex_string(string, length)
  204.     char           *string;
  205.     size_t          length;
  206. {
  207.     size_t          i;
  208.  
  209.     putchar('\'');
  210.     for (i = 0; i < length; i++) {
  211.         printf("%02hX", string[i]);
  212.     }
  213.     fputs("\'H", stdout);
  214. }
  215.  
  216. static void
  217. show_octet_string(string, length)
  218.     char           *string;
  219.     size_t          length;
  220. {
  221.     size_t          i;
  222.     unsigned char   c;
  223.  
  224.     for (i = 0; i < length; i++) {
  225.         if (!isprintable(string[i]))
  226.             break;
  227.     }
  228.     if (i < length)
  229.         show_hex_string(string, length);
  230.     else
  231.         show_string(string, length);
  232. }
  233.  
  234. static void
  235. show_bit_string(string, length)
  236.     char           *string;
  237.     size_t          length;
  238. {
  239.     size_t          i;
  240.     unsigned char   c;
  241.     unsigned char   mask;
  242.     unsigned char   first_unused_bit;
  243.  
  244.     if (1 > length)
  245.         punt("Bitstring length must be > 0.");
  246.     if (1 == length && 0 != *string)
  247.         punt("An empty bitstring must have no \
  248.               unused bits.");
  249.     if (7 < *string)
  250.         punt("can't have more than 7 unused bits \
  251.               in last octet.");
  252.     putchar('\'');
  253.     length--;
  254.     for (i = 1; i < length; i++) {
  255.         c = string[i];
  256.         for (mask = BIT_8; mask; mask >> = 1)
  257.             putchar(mask & c ? '1' : '0');
  258.     }
  259.     if (0 < length) {
  260.         first_unused_bit = (unsigned char)
  261.                            (1 << *string >> 1);
  262.         for (mask = BIT_8;
  263.              mask ^ first_unused_bit;
  264.              mask >> = 1)
  265.             putchar(mask & string[length] ? '1' : '0');
  266.     }
  267.     fputs("\'B", stdout);
  268. }
  269.  
  270. static void
  271. show_boolean(string, length)
  272.     char           *string;
  273.     size_t          length;
  274. {
  275.     if (0 == *string)
  276.         printf("FALSE");
  277.     else
  278.         printf("TRUE");
  279. }
  280.  
  281. static void
  282. show_integer(string, length)
  283.     char           *string;
  284.     size_t          length;
  285. {
  286.     signed char    *c;
  287.     signed char    *end;
  288.     long            x;
  289.  
  290.     x = 0;
  291.     end = string + length;
  292.     for (c = string; c < end; c++) {
  293.         x << = 8;
  294.         x |= *c;
  295.     }
  296.     printf("%ld", x);
  297. }
  298.  
  299. char           *
  300. show_value_notation(encoding, length, level)
  301.     char           *encoding;
  302.     size_t          length;
  303.     unsigned int    level;
  304. /*
  305.  * This function converts from transfer syntax to
  306.  * value notation. It returns a pointer to the octet
  307.  * past the encoding. It calls itself to decode
  308.  * constructed encodings.
  309.  */
  310. {
  311.     char           *next_octet;
  312.     int             i;
  313.     int             asn1_identifier;
  314.     size_t          asn1_length;
  315.     char           *asn1_contents;
  316.     unsigned short  id_class;
  317.     unsigned short  id_complexity;
  318.     unsigned short  id_tag_number;
  319.     static char    *class[] =
  320.     {"UNIVERSAL ", "APPLICATION ", "", "PRIVATE "};
  321.  
  322.     if (99 < level)
  323.         punt("We're in too deep.");
  324.     next_octet = encoding + length;
  325.     asn1_identifier = (unsigned char) *encoding;
  326.     id_class = the_class(encoding);
  327.     id_complexity = the_complexity(encoding);
  328.     id_tag_number = the_tag_number(&encod